import fnmatch
import os
import pickle
from dataStructs.my_hash import hgetall, hvals
from dataStructs.my_list import lrange
from dataStructs.my_set import smembers
from dataStructs.my_sortedset import zgetall
from dataStructs.my_string import get
from redisData.rServer import RS
from utils.key import get_all_keys

"""在这里记录client使用的具体的那个数据库信息"""


# 匹配字典
def match_keys(key_dict, pattern):
    matched_keys = []
    for key in key_dict.keys():
        if fnmatch.fnmatch(key, pattern):
            matched_keys.append(key)
    return matched_keys


# keys命令
def keys(cmd_list, rClient):
    """
    根据传入的字符串来匹配获取对应的键\n
    :param cmd_list:
    :param rClient: 客户端类实例
    :return: 所有符合条件的键
    """
    cmd_list.pop(0)
    if len(cmd_list) > 1:  # 如果传输的参数超过1
        return "(error)ERR wrong number of arguments for 'keys' command"

    try:  # 判断是否有传输了键
        key = cmd_list[0]  # 输入  * user* user? user[]
        key_dict = get_all_keys(rClient)  # 获取所有键
        results = match_keys(key_dict, key)  # 匹配键
        if len(results):
            result = '\n'.join(f'{index}) {item}' for index, item in enumerate(results))
            return result
        else:
            return "(empty list or set)"
    except:  # 如果没有传输键
        return "(error) ERR wrong number of arguments for 'keys' command"


# exists命令,返回键存在的个数
def exists(cmd_list, rClient):
    """
    exists命令,返回键存在的个数\n
    :param cmd_list:
    :param rClient:
    :return:
    """
    cmd_list.pop(0)
    try:  # 判断是否有传输了键
        count = 0
        key_dict = get_all_keys(rClient)  # 获取所有键
        for key in cmd_list:  # 键可以重复
            if key in key_dict:
                count += 1
        return f"(integer) {count}"
    except:  # 如果没有传输键
        return "(error) ERR wrong number of arguments for 'exists' command"


# 获取当前数据库中键的数量
def dbsize(cmd_list, rClient):
    """
    获取当前数据库中键的数量\n
    :param cmd_list:
    :param rClient:
    :return:
    """
    cmd_list.pop(0)
    if len(cmd_list):  # 如果列表还有元素，出错
        return "(error) ERR wrong number of arguments for 'dbsize' command"
    key_dict = get_all_keys(rClient)  # 获取所有键
    return f"(integer) {len(key_dict)}"


# 切换数据库
def select(cmd_list, rClient):
    """
    切换数据库\n
    :param cmd_list:
    :param rClient:
    :return:
    """
    cmd_list.pop(0)
    if len(cmd_list) == 1:  # 并且只有一个整数参数
        try:
            rdb_num = int(cmd_list[0])
            if rdb_num > RS.redisDbNum - 1 or rdb_num < 0:
                return "(error) ERR DB index is out of range"
            else:
                rClient.redisDbId = rdb_num
                return "OK"
        except ValueError:
            return "(error) ERR invalid DB index"

    else:
        return "(error) ERR wrong number of arguments for 'select' command"


#  删除当前数据库中的所有键
def flushdb(cmd_list, rClient):
    """
    删除当前数据库中的所有键\n
    :param cmd_list:
    :param rClient:
    :return:
    """
    if len(cmd_list) == 1:  # 只有一个方法名
        if RS.rDB[rClient.redisDbId].set_keys_null():
            return "OK"
        else:
            return "(error)"
    else:
        return "ERR syntax error"


# 删除所有数据库中的所有键
def flushall(cmd_list, rClient):
    """
    删除所有数据库中的所有键\n
    :param cmd_list:
    :param rClient:
    :return:
    """
    if len(cmd_list) == 1:  # 只有一个方法名
        for i in range(RS.redisDbNum):  # 获取服务器的数据库数量
            RS.rDB[i].set_keys_null()  # 清除每个数据库
        return "OK"
    else:
        return "ERR syntax error"


# 删除指定的一个或多个键
def del_keys(cmd_list, rClient):
    if len(cmd_list) == 1:  # 只有一个方法名
        return "ERR wrong number of arguments for 'del' command"
    else:
        cmd_list.pop(0)  # 移除函数名
        num = RS.rDB[rClient.redisDbId].del_key_list(cmd_list)
        return f"(integer) {num}"


########################################################################
# RDB数据持久化 (Redis DataBase)  加载操作
def Pyrdb_load():
    """
    RDB数据持久化  加载操作\n
    :param cmd_list:
    :param rClient:
    :return:
    """
    rdb_file_path = 'redisData/pyredis_databases.pyrdb'

    # 检查文件是否存在
    if os.path.exists(rdb_file_path) and os.path.getsize(rdb_file_path) > 0:
        # 从文件中加载RedisServer对象
        with open(rdb_file_path, 'rb') as file:
            loaded_RS = pickle.load(file)

        # 更新已导入的RS实例,这将替换旧的实例属性为加载的实例属性
        RS.__dict__.update(loaded_RS.__dict__)
        return "OK"
    else:
        return "RDB file does not exist or is empty"
    # # 从文件中加载RedisServer对象
    # with open('redisData/pyredis_databases.pyrdb', 'rb') as file:
    #     loaded_RS = pickle.load(file)
    #
    # # 更新已导入的RS实例,这将替换旧的实例属性为加载的实例属性
    # RS.__dict__.update(loaded_RS.__dict__)
    # return "OK"


# RDB数据持久化 (Redis DataBase)  save写入操作
def save(cmd_list, rClient):
    """
    RDB数据持久化  写入操作\n
    SAVE命令会阻塞Redis服务器进程，直到RDB文件创建完毕为止，在服务器进程阻塞期间，服务器不能处理任何命令请求：
    :param cmd_list:
    :param rClient:
    :return:
    """
    if len(cmd_list) != 1:
        return "(error) ERR wrong number of arguments for 'save' command"
    # 序列化RS对象到文件
    with open('redisData/pyredis_databases.pyrdb', 'wb') as file:
        pickle.dump(RS, file)
    return "OK"

# RDB数据持久化 (Redis DataBase)  bgsave写入操作
def BG_save(cmd_list, rClient):
    """
    BGSAVE命令会派生出一个子进程，然后由子进程负责创建RDB文件，服务器进程（父进程）继续处理命令请求：
    :param cmd_list:
    :param rClient:
    :return:
    """
    if len(cmd_list) != 1:
        return "(error) ERR wrong number of arguments for 'bgsave' command"
    save(cmd_list, rClient)
    return "Background saving started"

##################################################################
# AOF 数据持久化 (Append On File)
# AOF的写入功能
def AOF_write(logs):
    # 将列表中的字符串连接成一个以换行符分隔的字符串
    logs_str = '\n'.join(logs)
    # 将字符串写入文件
    with open('redisData/pyredis_aof_log.log', 'a') as file:
        file.write(logs_str)


# AOF的重写功能
def AOF_rewrite():
    print("AOF的重写功能！")


#显示所有键，类型，键值
def load_page(cmd_lists, rClient):
    if len(cmd_lists)==1:
        all_keys_dict=get_all_keys(rClient)
        keys=all_keys_dict.keys()
        list_keys=list(keys)
        types=all_keys_dict.values() 
        list_types=list(types)
        list_values=[]
        for key,type in zip(list_keys,list_types):
            if str(type)=="string":
                string_cmd_lists="get "+str(key)
                list_values.append(get(string_cmd_lists.split(),rClient))
            elif str(type)=="list":
                list_cmd_lists="lrange "+str(key)+" 0 999"
                list_values.append(lrange(list_cmd_lists.split(),rClient))
            elif str(type)=="hash":
                hash_cmd_lists="hgetall "+str(key)
                t=hgetall(hash_cmd_lists.split(),rClient)
                t=t.split("\n")
                t="\t".join(t)
                list_values.append(t)
            elif str(type)=="set":
                set_cmd_lists="smembers "+str(key)
                t=smembers(set_cmd_lists.split(),rClient)
                t=t.split("\n")
                t="\t".join(t)
                list_values.append(t)
            elif str(type)=="sortedset":
                sortedset_cmd_lists="zgetall "+str(key)
                t=zgetall(sortedset_cmd_lists.split(),rClient)
                t=t.split("\n")
                t="\t".join(t)
                list_values.append(t)       
                
        tmp=[]
        for i in range(len(list_keys)):
            tmp.append(f"{list_keys[i]} {list_types[i]} ")
        tmp="\n".join(tmp)
        return tmp    
            
    else:
        return "error"
    
    #条件查询
def details(cmd_lists,rClient):
    if len(cmd_lists)==2:
        all_keys_dict=get_all_keys(rClient)
        key=cmd_lists[1]
        if key in all_keys_dict:
            type=all_keys_dict[key]
            if str(type)=="string":
                    string_cmd_lists="get "+str(key)
                    return get(string_cmd_lists.split(),rClient)
            elif str(type)=="list":
                    list_cmd_lists="lrange "+str(key)+" 0 999"
                    return lrange(list_cmd_lists.split(),rClient)
            elif str(type)=="hash":
                    hash_cmd_lists="hgetall "+str(key)
                    return hgetall(hash_cmd_lists.split(),rClient)
            elif str(type)=="set":
                    set_cmd_lists="smembers "+str(key)
                    return smembers(set_cmd_lists.split(),rClient)
            elif str(type)=="sortedset":
                    sortedset_cmd_lists="zgetall "+str(key)
                    return zgetall(sortedset_cmd_lists.split(),rClient)
        else:
            return "key is not exisit"
    else: return "error"

def condi_search(cmd_lists,rClient):
    if len(cmd_lists)==2:
        all_keys_dict=get_all_keys(rClient)
        key=cmd_lists[1]
        if key in all_keys_dict:
            type=all_keys_dict[key]
            return str(key)+" "+str(type)
        else:
            return "key is not exisit"
    else: return "error"


